﻿#include "WRWorkTcpCommServerSocket.h"
#include "WRWorkTcpCommServerSession.h"
#include "../WRWorkTcpCommConsts.h"
#include "../WRWorkTcpCommHelper.h"

#include <QCoreApplication>

//注册初始事件类型。
static WR32s g_eventType = QEvent::registerEventType();

//初始化TCP服务会话。
WRWorkTcpCommServerSocket::WRWorkTcpCommServerSocket(WRWorkTcpCommServer* parent)
    : QTcpSocket(parent)
{
    m_available = 1;

    setReadBufferSize(WRWorkTcpComm::MaxDataSize);

    m_rBufLen = WRWorkTcpComm::MaxRecvSize;
    m_rBufArr = new char[m_rBufLen];
    m_rDatLen = 0;

    m_wStatus = false;
    m_wDatLen = 0;
    m_wDatPkg = 0;

    m_session = new WRWorkTcpCommServerSession(this);

    QObject::connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
    QObject::connect(this, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
    QObject::connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(onWritten(qint64)));
    QObject::connect(this, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
}

//释放当前对象所占用的相关资源。
WRWorkTcpCommServerSocket::~WRWorkTcpCommServerSocket()
{
    close();
    doClose();

    delete[] m_rBufArr;

    m_session->shutdown();
    m_session->release();
}

//执行关闭操作。
void WRWorkTcpCommServerSocket::doClose(void)
{
    m_wMutex.lock();
    if (m_available == -1)
    {
        m_wMutex.unlock();
        return;
    }
    m_available = -1;
    m_wMutex.unlock();

    QObject::disconnect(this, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
    QObject::disconnect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(onWritten(qint64)));
    QObject::disconnect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
    QObject::disconnect(this, SIGNAL(disconnected()), this, SLOT(onDisconnected()));

    if (m_wDatPkg)
    {
        m_wDatPkg->fulfil(-1);
        m_wDatPkg->release();
    }
    while(m_wQueue.count() > 0)
    {
        m_wDatPkg = m_wQueue.dequeue();
        m_wDatPkg->fulfil(-1);
        m_wDatPkg->release();
    }
    m_wDatPkg = 0;
}

//执行消息处理。
bool WRWorkTcpCommServerSocket::event(QEvent * e)
{
    if ((WR32s)(e->type()) == g_eventType)
    {
        doWritting();
        return true;
    }
    return QTcpSocket::event(e);
}

//执行数据写稿操作。
void WRWorkTcpCommServerSocket::doWritting(void)
{
    if (m_wDatPkg)
    {
        char* buffer;
        WR32s length = m_wDatPkg->buffer(&buffer);
        m_wDatLen += write(buffer + m_wDatLen, length - m_wDatLen);
        flush();
        if (m_wDatLen == length)
        {
            m_wDatPkg->fulfil(m_wDatLen);
            m_wDatPkg->release();
            m_wDatPkg = 0;
        }
    }
    else
    {
        m_wMutex.lock();
        if (m_wQueue.count() > 0)
        {
            m_wDatPkg = m_wQueue.dequeue();
            m_wMutex.unlock();

            char* buffer;
            WR32s length = m_wDatPkg->buffer(&buffer);
            m_wDatLen = write(buffer, length);
            if (m_wDatLen == length)
            {
                m_wDatPkg->fulfil(m_wDatLen);
                m_wDatPkg->release();
                m_wDatPkg = 0;
            }
        }
        else
        {
            m_wStatus = false;
            m_wMutex.unlock();
        }
    }
}

//处理接收到的数据，返回余下的数据长度。
WR32s WRWorkTcpCommServerSocket::process(const char* buf, WR32s len)
{
    while(len >= 8)
    {
        //寻找数据头
        WR32s idx = WRWorkTcpComm::checkHeader(buf, len);
        //未找到帧头，忽略所有数据
        if (idx < 0)
        {
            return 0;
        }
        //帧头非起始数据，数据出现丢失
        if (idx > 0)
        {
            buf += idx;
            len -= idx;
        }
        //数据长度不够，退出循化继续接收数据
        if (len < 8)
        {
            break;
        }
        //读取帧长
        WR32s l = WRBytes::read<WR32s>(buf + 4);
        //验证帧长度，以跳过假帧头
        if (l > WRWorkTcpComm::MaxDataSize)
        {
            buf += 4;
            len -= 4;
            continue;
        }
        //未接收到全部数据，退出循环并继续接收数据
        if (len < l)
        {
            break;
        }
        //验证帧尾部，如果不是帧尾，则表示前面的帧头为无效帧头，跳过
        if (WRBytes::read<WR32u>(buf + l - 4) != WRWorkTcpComm::FrameTailor)
        {
            buf += 4;
            len -= 4;
        }
        //验证版本，如果版本不正确，则表示前面的帧头是无效帧头，跳过
        if (WRBytes::read<WR32u>(buf + l - 8) != WRWorkTcpComm::FrameVersion)
        {
            buf +=4;
            len -= 4;
        }
        //进行数据帧处理，并将其后移
        m_session->procData(buf + 8, l - 16);
        buf += l;
        len -= l;
    }
    return len;
}

//当出现错误后调用此方法。
void WRWorkTcpCommServerSocket::onError(QAbstractSocket::SocketError)
{
    doClose();
}
//当断开连接后调用此方法。
void WRWorkTcpCommServerSocket::onDisconnected(void)
{
    doClose();
}

//当数据写入后调用此方法。
void WRWorkTcpCommServerSocket::onWritten(qint64)
{
    doWritting();
}
//当数据到来后调用此方法。
void WRWorkTcpCommServerSocket::onReadyRead(void)
{
    do
    {
        //读取数据。
        WR32s length = (WR32s)(read(m_rBufArr + m_rDatLen, m_rBufLen - m_rDatLen));
        if (length <= 0)
        {
            break;
        }
        m_rDatLen += length;
        //处理数据
        length = process(m_rBufArr, m_rDatLen);
        if (length >0 && length != m_rDatLen)
        {
            memmove(m_rBufArr, m_rBufArr + m_rDatLen - length, length);
        }
        m_rDatLen = length;
    }while(true);

    if (m_available != -1)
    {
        ++m_available;
    }
}

//执行写入操作。
bool WRWorkTcpCommServerSocket::process(WRDataPacket* packet)
{
    QMutexLocker locker(&m_wMutex);
    if (m_available != -1)
    {
        m_wQueue.enqueue(packet);
        if (!m_wStatus)
        {
            m_wStatus = true;
            QCoreApplication::postEvent(this, new QEvent((QEvent::Type)g_eventType));
        }
        return true;
    }
    return false;
}
